今天介紹的是資源管理中,delete
要注意是否需要delete []
,一起來看看吧!
今天的守則是:
Use the same form in corresponding uses of new and delete。
最開頭書中提供了一個例子:
std::string *stringArray = new std::string[100];
...
delete stringArray;
以上會有什麼問題呢?
結果會是undefined的,可以確信的一點是至少有99個被stringArray
指向的string object沒有被適當destroy,因為delete stringArray
,compiler只知道要去刪除一個stringArray object。
當我們用new
的時候,會做兩件事: 1. 分配memory;2. 該memory的相應constructors動起來;而delete
一樣會做兩件事: 1. memory對應的destructors被call起來;2. 釋放memory。
而其中有個重點就是,delete時被delete的pointer指向的是 一個單一物件 or 物件array?這很重要因為兩者的memory layout是不同的。通常array的memory會包含array的size,讓delete的時候可以知道要call多少destructor,而單一物件的memory就沒這東西。
而當我們對pointer使用delete的時候,delete要怎麼知道他要delete的memory是長什麼樣子呢?就只能依靠我們用[]
與否來告訴它了。有了[]
,delete就會認為要刪除的pointer指向的對象是array,就會知道要去讀例如array size,來知道要call哪些destructor─否則,delete一律當成要刪除的pointer就是一個single object。
正確用法就像這樣:
std::string *stringPtr1 = new std::string;
std::string *stringPtr2 = new std::string[100];
...
delete stringPtr1;
delete [] stringPtr2;
相對於最開頭的例子,如果這樣又會發生什麼事呢?
delete [] stringPtr1;
一樣,undefined,如上面所言,如果compiler存array的memory方式是先放array size,後面是那些物件,那delete操作就很可能誤將物件的memory解讀為array size,進而call了一堆不該call的destructor。
所以呼應今天的守則,規則非常簡單─如果在new
裡面有用[]
,那就要相對應的delete []
;反之亦然。
這在有多種constructor的class中特別需要注意,因為每個constructor都應該用一樣的new方式,例如都是single object,or都是array,這樣destructor裡面才能正確地destroy掉各種constructor new出來的物件!
還有一個地方也特別需要注意的─typedef。typedef應該特別註明使用到這類型的object時,應採用哪種delete方式,以符合它的type,例如以下:
typedef std::string AddressLines[4];
std::string *pal = new AddressLines;
delete pal; // undefined
delete [] pal; // fine
因為AddressLines
是array,所以它對應的delete應該也要是array。
而要避開這種潛在陷阱的辦法就是直接避開在typedef使用array types。這很簡單,就如之前有提過的([Day 19] Use objects to manage resources),因為C++ library裡面就有string
跟vector
這種templates,實在沒什麼需要自行動態分配array的地方。
貼心重點提醒:
- If you use
[]
in anew
expression, you must use[]
in the correspondingdelete
expression. If you don't use[]
in anew
expression, you mustn't use[]
in the correspondingdelete
expression.
不知道為什麼寫的這麼拗口XD 很簡單就是new有用到[]
,記得delete也要delete []
;反之如果沒有,就不要亂delete []
。